package cn.hrfax.stf.sdk.util;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

import com.alibaba.fastjson.JSONObject;

/**
 * @author yongSen.wang
 * @date 2020/7/14 15:36
 */
public class RSAUtil {
    private static final String ENCODE            = "UTF-8";
    private static final int    MAX_ENCRYPT_BLOCK = 117;
    private static final int    MAX_DECRYPT_BLOCK = 128;
    private static final String PUBLIC_KEY        = "publicKey";
    private static final String PRIVATE_KEY       = "privateKey";

    public static Map<String, Object> genKeyPair() {
        String pubKey = "";
        String prvKey = "";
        Map<String, Object> keyMap = new HashMap();
        try {
            KeyPair keypair = generateKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) keypair.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) keypair.getPrivate();
            pubKey = Base64Util.byteToStringBase64(publicKey.getEncoded());
            prvKey = Base64Util.byteToStringBase64(privateKey.getEncoded());
            keyMap.put("publicKey", pubKey);
            keyMap.put("privateKey", prvKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return keyMap;
    }

    private static KeyPair generateKeyPair() throws Exception {
        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            int KEY_SIZE = 1024;
            keyPairGen.initialize(1024);
            return keyPairGen.generateKeyPair();
        } catch (Exception e) {
            throw new Exception(e.getMessage());
        }
    }

    private static byte[] encryptByPublicKey(String data, String publicKey) throws Exception {
        byte[] encryptedData = data.getBytes("UTF-8");
        byte[] keyBytes = Base64Util.base64StringToByte(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(1, publicK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        int i = 0;
        while (inputLen - offSet > 0) {
            byte[] cache;
            if (inputLen - offSet > 117) {
                cache = cipher.doFinal(encryptedData, offSet, 117);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 117;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    private static byte[] decryptByPrivateKey(String data, String privateKey) throws Exception {
        byte[] encryptedData = Base64.decodeBase64(data);
        byte[] keyBytes = Base64Util.base64StringToByte(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(2, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;

        int i = 0;
        while (inputLen - offSet > 0) {
            byte[] cache;
            if (inputLen - offSet > 128) {
                cache = cipher.doFinal(encryptedData, offSet, 128);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * 128;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    }

    public static String encrypt(String data, String publicKey) {
        String encryptString = "";
        if (isNotEmpty(data)) {
            try {
                byte[] encryptData = encryptByPublicKey(data, publicKey);
                return Base64.encodeBase64String(encryptData);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return encryptString;
    }

    public static String decrypt(String data, String privateKey) {
        String decryptString = "";
        try {
            byte[] decryptData = decryptByPrivateKey(data, privateKey);
            return new String(decryptData, "UTF-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return decryptString;
    }

    public static final boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    public static final boolean isEmpty(String str) {
        if ((str == null) || (str.length() == 0) || ("null".equals(str))) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        // 加密数据
		String data = "{\n" +
                "    \"pub\": {\n" +
                "        \"bankCode\": \"0180400023\",\n" +
                "        \"assurerNo\": \"D36028222\",\n" +
                "        \"orderNo\": \"vxdb014020181123183720002\",\n" +
                "        \"platNo\": \"slnfdw\",\n" +
                "        \"busiCode\": \"1001\",\n" +
                "        \"productType\": 1\n" +
                "    },\n" +
                "    \"req\": {\n" +
                "        \"intentionPrice\": 200000,\n" +
                "        \"lender\": {\n" +
                "            \"familyAddress\": \"重庆市大足县龙岗街道双塔路112号2单元7-1\",\n" +
                "            \"endDate\": \"2035.07.14\",\n" +
                "            \"bankCardNo\": \"12345678912345\",\n" +
                "            \"idCard\": \"500225199002260015\",\n" +
                "            \"phoneNum\": \"13877777777\",\n" +
                "            \"signMode\": 2,\n" +
                "            \"issueAuthority\": \"青岛市公安局市北分局\",\n" +
                "            \"userName\": \"郭天亮\",\n" +
                "            \"pics\": [\n" +
                "                {\n" +
                "                    \"picFileName\": \"20181123-1838-17641-9e715402-9175-1bb4-92bf-96f7c652aea6.JPG\",\n" +
                "                    \"picAddress\": \"http://hrfax.oss-cn-hangzhou.aliyuncs.com/web/2018/vxdb014020181123183724495/20181123-1838-17641-9e715402-9175-1bb4-92bf-96f7c652aea6.JPG?x-oss-process=style/carloan\",\n" +
                "                    \"picId\": 322239001,\n" +
                "                    \"picCode\": \"sfzzm\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"picFileName\": \"20181123-1838-19805-a9308272-de36-fb4d-d2cb-af33a42c2e7d.JPG\",\n" +
                "                    \"picAddress\": \"http://hrfax.oss-cn-hangzhou.aliyuncs.com/web/2018/vxdb014020181123183724495/20181123-1838-19805-a9308272-de36-fb4d-d2cb-af33a42c2e7d.JPG?x-oss-process=style/carloan\",\n" +
                "                    \"picId\": 322239002,\n" +
                "                    \"picCode\": \"sfzfm\"\n" +
                "                },\n" +
                "                {\n" +
                "                    \"picFileName\": \"20181123-1838-21410-bd6e22ad-a82a-59d3-2320-b6e790407855.jpg\",\n" +
                "                    \"picAddress\": \"http://hrfax.oss-cn-hangzhou.aliyuncs.com/web/2018/vxdb014020181123183724495/20181123-1838-21410-bd6e22ad-a82a-59d3-2320-b6e790407855.jpg?x-oss-process=style/carloan\",\n" +
                "                    \"picId\": 322239003,\n" +
                "                    \"picCode\": \"zxsqs\"\n" +
                "                }\n" +
                "            ],\n" +
                "            \"startDate\": \"2015.07.14\"\n" +
                "        },\n" +
                "        \"carType\": 0,\n" +
                "        \"downloadMode\": 1,\n" +
                "        \"spouse\": []\n" +
                "    }\n" +
                "}";
        System.out.println(data);
        String dataPublicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCFZnUVz07wuQfI5kf3uOaaJcpq*W3yQhJnIX2k-EKwKZaSkyuXutk0TXqwT-GXxIQJqmkjLup*HN7H1uF7JMfxl00AnncHB82LqUQKQwf5wcdDTNhvKLQtjRoLE3ry6ARoYHu5AkZPKW7sMM4o*UegPlSr45p4ZsK0iVdjqmgZfwIDAQAB";
        String signPrivateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKOoelzwAU5Asw9zknkTYGvfZr0Ap6ZDL6NMSNRYZ2maVJd5xOfSRqTkEq1Ne*h2Qe3wCKdxo0SuCVWNjM-nd3af*fb4YcWdlDuHaA1s28I5hZtVp2sbF*nvgdeUwSz-X0hQGcaqVzcTKDH9l2XuMC**OEofyyosU2jvEIGdwqSNAgMBAAECgYAkojvxvc*tApKSbN5mt82nl-RZbmIYt4VcWmEbF0bevqsc1SccdVdW5a7AmE2aNY6AgnCNesR-RS3Vtr-Ech2tVfwMXypJsXN5hq0uyM6iDkE6kFhGL1zui72u9RQJvdB7CsNfEONIaFlX46MUOdF0fR2n-sGLMc1qzpj*L3k6QQJBAOJfQRF6ehE5d1Sm*7q9uObte1ubako89TSGZmCOk-3vpm9CRTey-18Ids98yMNg3Wy53M4oEzjwjdnnulX9PpUCQQC5E-NySYbigVCsO5Tjr*iAA1ykdGIgaRM45s2tvbMLYQdZYhnkPRjSj*Y7I915cp5klQ75T260InPYQqBkb2gZAkEAjRYtKcWZ*s5EL4B7eCHy8gqlTa0JjAd*FCSH-joexq-snX9CQLrRKtvNoPf28L6YgsE8e0jC4kQbROqGWj2iGQJBAKkXVUCBdL7UrsPs26b6PE1YxPdrbYt29Jz0Ic4ulro6t*AuBMHGIDugRRSbO*mNkrEKjlew-s*M*pIGrUuVjWECQQC3qMemXCmqp7lAaSqYy9Rk8HNVgEeDqJfhcIS4SrRH0DSExPE9yfhadaiC4IIYmmK5L*2V3dxIUI7KXbeO*ptz";

//		String assurerNo = "ceshi001";
//		String bankType = "ICBC";
//		String busiCode = "0001";
//		String platNo = "zajk";
        String assurerNo = "D36028222";
        String bankType = "ICBC";
        String busiCode = "1001";
        String platNo = "slnfdw";
        JSONObject json = encryptData(data, dataPublicKey, signPrivateKey, assurerNo, bankType, busiCode, platNo);
        System.err.println(json);
        //解密

        //验签

    }

    public static JSONObject encryptData(String data, String dataPublicKey ,String signPrivateKey ,String assurerNo
            , String bankType, String busiCode, String platNo){
        JSONObject request = new JSONObject();
        String encryptData = RSAUtil.encrypt(data, dataPublicKey);
        request.put("data", encryptData);
        String signData = RSASignature.sign(data, signPrivateKey);
        request.put("sign", signData);
        request.put("assurerNo", assurerNo);
        request.put("bankType", bankType);
        request.put("busiCode", busiCode);
        request.put("platNo", platNo);
        request.put("bankCode","0180400023");
        return request;
    }

}
